/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the  "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
 * $Id$
 */
package wx.xml.xalan.xalan.templates;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;

import javax.xml.transform.TransformerException;

import wx.xml.xalan.xalan.res.XSLTErrorResources;
import wx.xml.xalan.xml.dtm.DTM;
import wx.xml.xalan.xml.utils.QName;
import wx.xml.xalan.xpath.Expression;
import wx.xml.xalan.xpath.XPath;
import wx.xml.xalan.xpath.XPathContext;
import wx.xml.xalan.xpath.compiler.PsuedoNames;
import wx.xml.xalan.xpath.patterns.NodeTest;
import wx.xml.xalan.xpath.patterns.StepPattern;
import wx.xml.xalan.xpath.patterns.UnionPattern;

/**
 * Encapsulates a template list, and helps locate individual templates.
 *
 * @xsl.usage advanced
 */
public class TemplateList implements java.io.Serializable {
    static final long serialVersionUID = 5803675288911728791L;
    /**
     * Flag to indicate whether in DEBUG mode
     */
    final static boolean DEBUG = false;
    /**
     * Keyed on string macro names, and holding values
     * that are macro elements in the XSL DOM tree.
     * Initialized in initMacroLookupTable, and used in
     * findNamedTemplate.
     *
     * @serial
     */
    private Hashtable m_namedTemplates = new Hashtable(89);
    /**
     * This table is keyed on the target elements
     * of patterns, and contains linked lists of
     * the actual patterns that match the target element
     * to some degree of specifity.
     *
     * @serial
     */
    private Hashtable m_patternTable = new Hashtable(89);
    /**
     * Wildcard patterns.
     *
     * @serial
     */
    private TemplateSubPatternAssociation m_wildCardPatterns = null;
    /**
     * Text Patterns.
     *
     * @serial
     */
    private TemplateSubPatternAssociation m_textPatterns = null;
    /**
     * Root document Patterns.
     *
     * @serial
     */
    private TemplateSubPatternAssociation m_docPatterns = null;
    /**
     * Comment Patterns.
     *
     * @serial
     */
    private TemplateSubPatternAssociation m_commentPatterns = null;

    /**
     * Construct a TemplateList object. Needs to be public so it can
     * be invoked from the CompilingStylesheetHandler.
     */
    public TemplateList() {
        super();
    }

    /**
     * Add a template to the table of named templates and/or the table of templates
     * with match patterns.  This routine should
     * be called in decreasing order of precedence but it checks nonetheless.
     *
     * @param template
     */
    public void setTemplate(ElemTemplate template) {
        XPath matchXPath = template.getMatch();

        if (null == template.getName() && null == matchXPath) {
            template.error(XSLTErrorResources.ER_NEED_NAME_OR_MATCH_ATTRIB,
                new Object[]{"xsl:template"});
        }

        if (null != template.getName()) {
            ElemTemplate existingTemplate = (ElemTemplate) m_namedTemplates.get(template.getName());
            if (null == existingTemplate) {
                m_namedTemplates.put(template.getName(), template);
            } else {
                int existingPrecedence =
                    existingTemplate.getStylesheetComposed().getImportCountComposed();
                int newPrecedence = template.getStylesheetComposed().getImportCountComposed();
                if (newPrecedence > existingPrecedence) {
                    // This should never happen
                    m_namedTemplates.put(template.getName(), template);
                } else if (newPrecedence == existingPrecedence)
                    template.error(XSLTErrorResources.ER_DUPLICATE_NAMED_TEMPLATE,
                        new Object[]{template.getName()});
            }
        }


        if (null != matchXPath) {
            Expression matchExpr = matchXPath.getExpression();

            if (matchExpr instanceof StepPattern) {
                insertPatternInTable((StepPattern) matchExpr, template);
            } else if (matchExpr instanceof UnionPattern) {
                UnionPattern  upat = (UnionPattern) matchExpr;
                StepPattern[] pats = upat.getPatterns();
                int           n    = pats.length;

                for (int i = 0; i < n; i++) {
                    insertPatternInTable(pats[i], template);
                }
            } else {

                // TODO: assert error
            }
        }
    }

    /**
     * Dump all patterns and elements that match those patterns
     */
    void dumpAssociationTables() {

        Enumeration associations = m_patternTable.elements();

        while (associations.hasMoreElements()) {
            TemplateSubPatternAssociation head =
                (TemplateSubPatternAssociation) associations.nextElement();

            while (null != head) {
                System.out.print("(" + head.getTargetString() + ", "
                    + head.getPattern() + ")");

                head = head.getNext();
            }

            System.out.println("\n.....");
        }

        TemplateSubPatternAssociation head = m_wildCardPatterns;

        System.out.print("wild card list: ");

        while (null != head) {
            System.out.print("(" + head.getTargetString() + ", "
                + head.getPattern() + ")");

            head = head.getNext();
        }

        System.out.println("\n.....");
    }

    /**
     * After all templates have been added, this function
     * should be called.
     */
    public void compose(StylesheetRoot sroot) {

        if (DEBUG) {
            System.out.println("Before wildcard insert...");
            dumpAssociationTables();
        }

        if (null != m_wildCardPatterns) {
            Enumeration associations = m_patternTable.elements();

            while (associations.hasMoreElements()) {
                TemplateSubPatternAssociation head =
                    (TemplateSubPatternAssociation) associations.nextElement();
                TemplateSubPatternAssociation wild = m_wildCardPatterns;

                while (null != wild) {
                    try {
                        head = insertAssociationIntoList(
                            head, (TemplateSubPatternAssociation) wild.clone(), true);
                    } catch (CloneNotSupportedException cnse) {
                    }

                    wild = wild.getNext();
                }
            }
        }

        if (DEBUG) {
            System.out.println("After wildcard insert...");
            dumpAssociationTables();
        }
    }

    /**
     * Insert the given TemplateSubPatternAssociation into the the linked
     * list.  Sort by import precedence, then priority, then by document order.
     *
     * @param head             The first TemplateSubPatternAssociation in the linked list.
     * @param item             The item that we want to insert into the proper place.
     * @param isWildCardInsert <code>true</code> if we are inserting a wild card
     *                         template onto this list.
     * @return the new head of the list.
     */
    private TemplateSubPatternAssociation
    insertAssociationIntoList(TemplateSubPatternAssociation head,
                              TemplateSubPatternAssociation item,
                              boolean isWildCardInsert) {

        // Sort first by import level (higher level is at front),
        // then by priority (highest priority is at front),
        // then by document order (later in document is at front).

        double                        priority    = getPriorityOrScore(item);
        double                        workPriority;
        int                           importLevel = item.getImportLevel();
        int                           docOrder    = item.getDocOrderPos();
        TemplateSubPatternAssociation insertPoint = head;
        TemplateSubPatternAssociation next;
        boolean                       insertBefore;         // true means insert before insertPoint; otherwise after
        // This can only be true if insertPoint is pointing to
        // the first or last template.

        // Spin down so that insertPoint points to:
        // (a) the template immediately _before_ the first template on the chain with
        // a precedence that is either (i) less than ours or (ii) the same as ours but
        // the template document position is less than ours
        // -or-
        // (b) the last template on the chain if no such template described in (a) exists.
        // If we are pointing to the first template or the last template (that is, case b),
        // we need to determine whether to insert before or after the template.  Otherwise,
        // we always insert after the insertPoint.

        while (true) {
            next = insertPoint.getNext();
            if (null == next)
                break;
            else {
                workPriority = getPriorityOrScore(next);
                if (importLevel > next.getImportLevel())
                    break;
                else if (importLevel < next.getImportLevel())
                    insertPoint = next;
                else if (priority > workPriority)               // import precedence is equal
                    break;
                else if (priority < workPriority)
                    insertPoint = next;
                else if (docOrder >= next.getDocOrderPos())     // priorities, import are equal
                    break;
                else
                    insertPoint = next;
            }
        }

        if ((null == next) || (insertPoint == head))      // insert point is first or last
        {
            workPriority = getPriorityOrScore(insertPoint);
            if (importLevel > insertPoint.getImportLevel())
                insertBefore = true;
            else if (importLevel < insertPoint.getImportLevel())
                insertBefore = false;
            else if (priority > workPriority)
                insertBefore = true;
            else if (priority < workPriority)
                insertBefore = false;
            else if (docOrder >= insertPoint.getDocOrderPos())
                insertBefore = true;
            else
                insertBefore = false;
        } else
            insertBefore = false;

        // System.out.println("appending: "+target+" to "+matchPat.getPattern());

        if (isWildCardInsert) {
            if (insertBefore) {
                item.setNext(insertPoint);

                String key = insertPoint.getTargetString();

                item.setTargetString(key);
                putHead(key, item);
                return item;
            } else {
                item.setNext(next);
                insertPoint.setNext(item);
                return head;
            }
        } else {
            if (insertBefore) {
                item.setNext(insertPoint);

                if (insertPoint.isWild() || item.isWild())
                    m_wildCardPatterns = item;
                else
                    putHead(item.getTargetString(), item);
                return item;
            } else {
                item.setNext(next);
                insertPoint.setNext(item);
                return head;
            }
        }
    }

    /**
     * Add a template to the template list.
     *
     * @param pattern
     * @param template
     */
    private void insertPatternInTable(StepPattern pattern, ElemTemplate template) {

        String target = pattern.getTargetString();

        if (null != target) {
            String pstring = template.getMatch().getPatternString();
            TemplateSubPatternAssociation association =
                new TemplateSubPatternAssociation(template, pattern, pstring);

            // See if there's already one there
            boolean isWildCard = association.isWild();
            TemplateSubPatternAssociation head = isWildCard
                                                 ? m_wildCardPatterns
                                                 : getHead(target);

            if (null == head) {
                if (isWildCard)
                    m_wildCardPatterns = association;
                else
                    putHead(target, association);
            } else {
                insertAssociationIntoList(head, association, false);
            }
        }
    }

    /**
     * Given a match pattern and template association, return the
     * score of that match.  This score or priority can always be
     * statically calculated.
     *
     * @param matchPat The match pattern to template association.
     * @return {@link wx.xml.xalan.xpath.patterns.NodeTest#SCORE_NODETEST},
     * {@link wx.xml.xalan.xpath.patterns.NodeTest#SCORE_NONE},
     * {@link wx.xml.xalan.xpath.patterns.NodeTest#SCORE_NSWILD},
     * {@link wx.xml.xalan.xpath.patterns.NodeTest#SCORE_QNAME}, or
     * {@link wx.xml.xalan.xpath.patterns.NodeTest#SCORE_OTHER}, or
     * the value defined by the priority attribute of the template.
     */
    private double getPriorityOrScore(TemplateSubPatternAssociation matchPat) {

        double priority = matchPat.getTemplate().getPriority();

        if (priority == XPath.MATCH_SCORE_NONE) {
            Expression ex = matchPat.getStepPattern();

            if (ex instanceof NodeTest) {
                return ((NodeTest) ex).getDefaultScore();
            }
        }

        return priority;
    }

    /**
     * Locate a named template.
     *
     * @param qname Qualified name of the template.
     * @return Template argument with the requested name, or null if not found.
     */
    public ElemTemplate getTemplate(QName qname) {
        return (ElemTemplate) m_namedTemplates.get(qname);
    }

    /**
     * Get the head of the most likely list of associations to check, based on
     * the name and type of the targetNode argument.
     *
     * @param xctxt      The XPath runtime context.
     * @param targetNode The target node that will be checked for a match.
     * @param dtm        The dtm owner for the target node.
     * @return The head of a linked list that contains all possible match pattern to
     * template associations.
     */
    public TemplateSubPatternAssociation getHead(XPathContext xctxt,
                                                 int targetNode, DTM dtm) {
        short                         targetNodeType = dtm.getNodeType(targetNode);
        TemplateSubPatternAssociation head;

        switch (targetNodeType) {
            case DTM.ELEMENT_NODE:
            case DTM.ATTRIBUTE_NODE:
                head = (TemplateSubPatternAssociation) m_patternTable.get(
                    dtm.getLocalName(targetNode));
                break;
            case DTM.TEXT_NODE:
            case DTM.CDATA_SECTION_NODE:
                head = m_textPatterns;
                break;
            case DTM.ENTITY_REFERENCE_NODE:
            case DTM.ENTITY_NODE:
                head = (TemplateSubPatternAssociation) m_patternTable.get(
                    dtm.getNodeName(targetNode)); // %REVIEW% I think this is right
                break;
            case DTM.PROCESSING_INSTRUCTION_NODE:
                head = (TemplateSubPatternAssociation) m_patternTable.get(
                    dtm.getLocalName(targetNode));
                break;
            case DTM.COMMENT_NODE:
                head = m_commentPatterns;
                break;
            case DTM.DOCUMENT_NODE:
            case DTM.DOCUMENT_FRAGMENT_NODE:
                head = m_docPatterns;
                break;
            case DTM.NOTATION_NODE:
            default:
                head = (TemplateSubPatternAssociation) m_patternTable.get(
                    dtm.getNodeName(targetNode)); // %REVIEW% I think this is right
        }

        return (null == head) ? m_wildCardPatterns : head;
    }

    /**
     * Given a target element, find the template that best
     * matches in the given XSL document, according
     * to the rules specified in the xsl draft.  This variation of getTemplate
     * assumes the current node and current expression node have already been
     * pushed.
     *
     * @param xctxt
     * @param targetNode
     * @param mode                  A string indicating the display mode.
     * @param maxImportLevel        The maximum importCountComposed that we should consider or -1
     *                              if we should consider all import levels.  This is used by apply-imports to
     *                              access templates that have been overridden.
     * @param quietConflictWarnings
     * @return Rule that best matches targetElem.
     * @throws XSLProcessorException thrown if the active ProblemListener and XPathContext decide
     *                               the error condition is severe enough to halt processing.
     * @throws TransformerException
     */
    public ElemTemplate getTemplateFast(XPathContext xctxt,
                                        int targetNode,
                                        int expTypeID,
                                        QName mode,
                                        int maxImportLevel,
                                        boolean quietConflictWarnings,
                                        DTM dtm)
        throws TransformerException {

        TemplateSubPatternAssociation head;

        switch (dtm.getNodeType(targetNode)) {
            case DTM.ELEMENT_NODE:
            case DTM.ATTRIBUTE_NODE:
                head = (TemplateSubPatternAssociation) m_patternTable.get(
                    dtm.getLocalNameFromExpandedNameID(expTypeID));
                break;
            case DTM.TEXT_NODE:
            case DTM.CDATA_SECTION_NODE:
                head = m_textPatterns;
                break;
            case DTM.ENTITY_REFERENCE_NODE:
            case DTM.ENTITY_NODE:
                head = (TemplateSubPatternAssociation) m_patternTable.get(
                    dtm.getNodeName(targetNode)); // %REVIEW% I think this is right
                break;
            case DTM.PROCESSING_INSTRUCTION_NODE:
                head = (TemplateSubPatternAssociation) m_patternTable.get(
                    dtm.getLocalName(targetNode));
                break;
            case DTM.COMMENT_NODE:
                head = m_commentPatterns;
                break;
            case DTM.DOCUMENT_NODE:
            case DTM.DOCUMENT_FRAGMENT_NODE:
                head = m_docPatterns;
                break;
            case DTM.NOTATION_NODE:
            default:
                head = (TemplateSubPatternAssociation) m_patternTable.get(
                    dtm.getNodeName(targetNode)); // %REVIEW% I think this is right
        }

        if (null == head) {
            head = m_wildCardPatterns;
            if (null == head)
                return null;
        }

        // XSLT functions, such as xsl:key, need to be able to get to
        // current ElemTemplateElement via a cast to the prefix resolver.
        // Setting this fixes bug idkey03.
        xctxt.pushNamespaceContextNull();
        try {
            do {
                if ((maxImportLevel > -1) && (head.getImportLevel() > maxImportLevel)) {
                    continue;
                }
                ElemTemplate template = head.getTemplate();
                xctxt.setNamespaceContext(template);

                if ((head.m_stepPattern.execute(xctxt, targetNode, dtm, expTypeID) != NodeTest.SCORE_NONE)
                    && head.matchMode(mode)) {
                    if (quietConflictWarnings)
                        checkConflicts(head, xctxt, targetNode, mode);

                    return template;
                }
            }
            while (null != (head = head.getNext()));
        } finally {
            xctxt.popNamespaceContext();
        }

        return null;
    }  // end findTemplate

    /**
     * Given a target element, find the template that best
     * matches in the given XSL document, according
     * to the rules specified in the xsl draft.
     *
     * @param xctxt
     * @param targetNode
     * @param mode                  A string indicating the display mode.
     * @param quietConflictWarnings
     * @return Rule that best matches targetElem.
     * @throws XSLProcessorException thrown if the active ProblemListener and XPathContext decide
     *                               the error condition is severe enough to halt processing.
     * @throws TransformerException
     */
    public ElemTemplate getTemplate(XPathContext xctxt,
                                    int targetNode,
                                    QName mode,
                                    boolean quietConflictWarnings,
                                    DTM dtm)
        throws TransformerException {

        TemplateSubPatternAssociation head = getHead(xctxt, targetNode, dtm);

        if (null != head) {
            // XSLT functions, such as xsl:key, need to be able to get to
            // current ElemTemplateElement via a cast to the prefix resolver.
            // Setting this fixes bug idkey03.
            xctxt.pushNamespaceContextNull();
            xctxt.pushCurrentNodeAndExpression(targetNode, targetNode);
            try {
                do {
                    ElemTemplate template = head.getTemplate();
                    xctxt.setNamespaceContext(template);

                    if ((head.m_stepPattern.execute(xctxt, targetNode) != NodeTest.SCORE_NONE)
                        && head.matchMode(mode)) {
                        if (quietConflictWarnings)
                            checkConflicts(head, xctxt, targetNode, mode);

                        return template;
                    }
                }
                while (null != (head = head.getNext()));
            } finally {
                xctxt.popCurrentNodeAndExpression();
                xctxt.popNamespaceContext();
            }
        }

        return null;
    }  // end findTemplate

    /**
     * Given a target element, find the template that best
     * matches in the given XSL document, according
     * to the rules specified in the xsl draft.
     *
     * @param xctxt
     * @param targetNode
     * @param mode                  A string indicating the display mode.
     * @param maxImportLevel        The maximum importCountComposed that we should consider or -1
     *                              if we should consider all import levels.  This is used by apply-imports to
     *                              access templates that have been overridden.
     * @param endImportLevel        The count of composed imports
     * @param quietConflictWarnings
     * @return Rule that best matches targetElem.
     * @throws XSLProcessorException thrown if the active ProblemListener and XPathContext decide
     *                               the error condition is severe enough to halt processing.
     * @throws TransformerException
     */
    public ElemTemplate getTemplate(XPathContext xctxt,
                                    int targetNode,
                                    QName mode,
                                    int maxImportLevel, int endImportLevel,
                                    boolean quietConflictWarnings,
                                    DTM dtm)
        throws TransformerException {

        TemplateSubPatternAssociation head = getHead(xctxt, targetNode, dtm);

        if (null != head) {
            // XSLT functions, such as xsl:key, need to be able to get to
            // current ElemTemplateElement via a cast to the prefix resolver.
            // Setting this fixes bug idkey03.
            xctxt.pushNamespaceContextNull();
            xctxt.pushCurrentNodeAndExpression(targetNode, targetNode);
            try {
                do {
                    if ((maxImportLevel > -1) && (head.getImportLevel() > maxImportLevel)) {
                        continue;
                    }
                    if (head.getImportLevel() <= maxImportLevel - endImportLevel)
                        return null;
                    ElemTemplate template = head.getTemplate();
                    xctxt.setNamespaceContext(template);

                    if ((head.m_stepPattern.execute(xctxt, targetNode) != NodeTest.SCORE_NONE)
                        && head.matchMode(mode)) {
                        if (quietConflictWarnings)
                            checkConflicts(head, xctxt, targetNode, mode);

                        return template;
                    }
                }
                while (null != (head = head.getNext()));
            } finally {
                xctxt.popCurrentNodeAndExpression();
                xctxt.popNamespaceContext();
            }
        }

        return null;
    }  // end findTemplate

    /**
     * Get a TemplateWalker for use by a compiler.  See the documentation for
     * the TreeWalker inner class for further details.
     */
    public TemplateWalker getWalker() {
        return new TemplateWalker();
    }

    /**
     * Check for match conflicts, and warn the stylesheet author.
     *
     * @param head       Template pattern
     * @param xctxt      Current XPath context
     * @param targetNode Node matching the pattern
     * @param mode       reference, which may be null, to the <a href="http://www.w3.org/TR/xslt#modes">current mode</a>.
     */
    private void checkConflicts(TemplateSubPatternAssociation head,
                                XPathContext xctxt, int targetNode, QName mode) {

        // TODO: Check for conflicts.
    }

    /**
     * Add object to vector if not already there.
     *
     * @param obj
     * @param v
     */
    private void addObjectIfNotFound(Object obj, Vector v) {

        int     n     = v.size();
        boolean addIt = true;

        for (int i = 0; i < n; i++) {
            if (v.elementAt(i) == obj) {
                addIt = false;

                break;
            }
        }

        if (addIt) {
            v.addElement(obj);
        }
    }

    /**
     * Get table of named Templates.
     * These are keyed on template names, and holding values
     * that are template elements.
     *
     * @return A Hashtable dictionary that contains {@link java.lang.String}s
     * as the keys, and {@link wx.xml.xalan.xalan.templates.ElemTemplate}s as the
     * values.
     */
    private Hashtable getNamedTemplates() {
        return m_namedTemplates;
    }

    /**
     * Set table of named Templates.
     * These are keyed on string macro names, and holding values
     * that are template elements in the XSL DOM tree.
     *
     * @param v Hashtable dictionary that contains {@link java.lang.String}s
     *          as the keys, and {@link wx.xml.xalan.xalan.templates.ElemTemplate}s as the
     *          values.
     */
    private void setNamedTemplates(Hashtable v) {
        m_namedTemplates = v;
    }

    /**
     * Get the head of the assocation list that is keyed by target.
     *
     * @param key The name of a node.
     * @return The head of a linked list that contains all possible match pattern to
     * template associations for the given key.
     */
    private TemplateSubPatternAssociation getHead(String key) {
        return (TemplateSubPatternAssociation) m_patternTable.get(key);
    }

    /**
     * Get the head of the assocation list that is keyed by target.
     *
     * @param key
     * @param assoc
     */
    private void putHead(String key, TemplateSubPatternAssociation assoc) {

        if (key.equals(PsuedoNames.PSEUDONAME_TEXT))
            m_textPatterns = assoc;
        else if (key.equals(PsuedoNames.PSEUDONAME_ROOT))
            m_docPatterns = assoc;
        else if (key.equals(PsuedoNames.PSEUDONAME_COMMENT))
            m_commentPatterns = assoc;

        m_patternTable.put(key, assoc);
    }

    /**
     * An inner class used by a compiler to iterate over all of the ElemTemplates
     * stored in this TemplateList.  The compiler can replace returned templates
     * with their compiled equivalent.
     */
    public class TemplateWalker {
        private Enumeration                   hashIterator;
        private boolean                       inPatterns;
        private TemplateSubPatternAssociation curPattern;

        private Hashtable m_compilerCache = new Hashtable();

        private TemplateWalker() {
            hashIterator = m_patternTable.elements();
            inPatterns = true;
            curPattern = null;
        }

        public ElemTemplate next() {

            ElemTemplate retValue = null;
            ElemTemplate ct;

            while (true) {
                if (inPatterns) {
                    if (null != curPattern)
                        curPattern = curPattern.getNext();

                    if (null != curPattern)
                        retValue = curPattern.getTemplate();
                    else {
                        if (hashIterator.hasMoreElements()) {
                            curPattern = (TemplateSubPatternAssociation) hashIterator.nextElement();
                            retValue = curPattern.getTemplate();
                        } else {
                            inPatterns = false;
                            hashIterator = m_namedTemplates.elements();
                        }
                    }
                }

                if (!inPatterns) {
                    if (hashIterator.hasMoreElements())
                        retValue = (ElemTemplate) hashIterator.nextElement();
                    else
                        return null;
                }

                ct = (ElemTemplate) m_compilerCache.get(new Integer(retValue.getUid()));
                if (null == ct) {
                    m_compilerCache.put(new Integer(retValue.getUid()), retValue);
                    return retValue;
                }
            }
        }
    }

}
